package com.zhtools.wx.bean;

import com.zhtools.utils.DateUtils;
import com.zhtools.wx.exception.WXPayException;
import com.zhtools.wx.utils.WXPayUtil;
import org.apache.commons.lang.StringUtils;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;

/**
 * @author zhanghao
 * 微信支付回调返回值封装
 */
public class WXPayCallBackResponse implements Serializable {
    private static final long serialVersionUID = 535938426446811450L;

    private static final String SIGNATURE_FAIL_EXCEPTION = "微信回调签名失败";
    private static final String BODY_EMPTY_EXCEPTION = "微信回调请求体内容为空";
    private static final String TRANSFORM_EXCEPTION = "微信回调请求体内容转换异常";
    private static final String PATTERN = "yyyyMMddHHmmss";

    private String transactionId;
    private String orderCode;
    private String openId;
    private Date payTime;
    private String isSubscribe;
    private String tradeType;
    private String bankType;
    private Integer totalFee;
    private Integer settlementTotalFee;
    private String feeType;
    private Integer cashFee;
    private String cashFeeType;
    private Integer couponFee;
    private Integer couponCount;
    private String attach;
    private List<Coupon> coupons;

    public String getTransactionId() {
        return transactionId;
    }

    public void setTransactionId(String transactionId) {
        this.transactionId = transactionId;
    }

    public String getOrderCode() {
        return orderCode;
    }

    public void setOrderCode(String orderCode) {
        this.orderCode = orderCode;
    }

    public String getOpenId() {
        return openId;
    }

    public void setOpenId(String openId) {
        this.openId = openId;
    }

    public Date getPayTime() {
        return payTime;
    }

    public void setPayTime(Date payTime) {
        this.payTime = payTime;
    }

    public String getIsSubscribe() {
        return isSubscribe;
    }

    public void setIsSubscribe(String isSubscribe) {
        this.isSubscribe = isSubscribe;
    }

    public String getTradeType() {
        return tradeType;
    }

    public void setTradeType(String tradeType) {
        this.tradeType = tradeType;
    }

    public String getBankType() {
        return bankType;
    }

    public void setBankType(String bankType) {
        this.bankType = bankType;
    }

    public Integer getTotalFee() {
        return totalFee;
    }

    public void setTotalFee(Integer totalFee) {
        this.totalFee = totalFee;
    }

    public Integer getSettlementTotalFee() {
        return settlementTotalFee;
    }

    public void setSettlementTotalFee(Integer settlementTotalFee) {
        this.settlementTotalFee = settlementTotalFee;
    }

    public String getFeeType() {
        return feeType;
    }

    public void setFeeType(String feeType) {
        this.feeType = feeType;
    }

    public Integer getCashFee() {
        return cashFee;
    }

    public void setCashFee(Integer cashFee) {
        this.cashFee = cashFee;
    }

    public String getCashFeeType() {
        return cashFeeType;
    }

    public void setCashFeeType(String cashFeeType) {
        this.cashFeeType = cashFeeType;
    }

    public Integer getCouponFee() {
        return couponFee;
    }

    public void setCouponFee(Integer couponFee) {
        this.couponFee = couponFee;
    }

    public Integer getCouponCount() {
        return couponCount;
    }

    public void setCouponCount(Integer couponCount) {
        this.couponCount = couponCount;
    }

    public String getAttach() {
        return attach;
    }

    public void setAttach(String attach) {
        this.attach = attach;
    }

    public List<Coupon> getCoupons() {
        return coupons;
    }

    public void setCoupons(List<Coupon> coupons) {
        this.coupons = coupons;
    }

    @Override
    public String toString() {
        return "WXPayCallBackResponse{" +
                "transactionId='" + transactionId + '\'' +
                ", orderCode='" + orderCode + '\'' +
                ", openId='" + openId + '\'' +
                ", payTime=" + payTime +
                ", isSubscribe='" + isSubscribe + '\'' +
                ", tradeType='" + tradeType + '\'' +
                ", bankType='" + bankType + '\'' +
                ", totalFee=" + totalFee +
                ", settlementTotalFee=" + settlementTotalFee +
                ", feeType='" + feeType + '\'' +
                ", cashFee=" + cashFee +
                ", cashFeeType='" + cashFeeType + '\'' +
                ", couponFee=" + couponFee +
                ", couponCount=" + couponCount +
                ", attach='" + attach + '\'' +
                ", coupons=" + coupons +
                '}';
    }

    /**
     * 请求报文转成bean
     */
    public static WXPayCallBackResponse formXmlResponse(String body, String signKey) throws WXPayException {
        if (StringUtils.isEmpty(body)) {
            throw new WXPayException(BODY_EMPTY_EXCEPTION);
        }
        boolean checkSign = false;
        try {
            checkSign = WXPayUtil.isSignatureValid(body, signKey);
        } catch (Exception e) {
            throw new WXPayException(SIGNATURE_FAIL_EXCEPTION, e);
        }
        if (!checkSign) {
            throw new WXPayException(SIGNATURE_FAIL_EXCEPTION);
        }

        Map<String, String> map = null;
        try {
            map = WXPayUtil.xmlToMap(body);
        } catch (Exception e) {
            throw new WXPayException(TRANSFORM_EXCEPTION, e);
        }
        String return_code = map.get("return_code");
        if ("FAIL".equals(return_code)) {
            String return_msg = map.get("return_msg");
            throw new WXPayException(return_msg);
        }
        String result_code = map.get("result_code");
        if ("FAIL".equals(result_code)) {
            String err_code = map.get("err_code");
            String err_code_des = map.get("err_code_des");
            String msg = "errorCode:" + err_code + ";errCodeDes:" + err_code_des;
            throw new WXPayException(msg);
        }
        String transaction_id = map.get("transaction_id");
        String out_trade_no = map.get("out_trade_no");
        String time_end = map.get("time_end");
        String openId = map.get("openid");

        WXPayCallBackResponse payResult = new WXPayCallBackResponse();
        payResult.setOpenId(openId);
        payResult.setOrderCode(out_trade_no);
        payResult.setTransactionId(transaction_id);
        payResult.setPayTime(DateUtils.stringToDate(time_end, PATTERN));
        payResult.setIsSubscribe(map.get("is_subscribe"));
        payResult.setTradeType(map.get("trade_type"));
        payResult.setBankType(map.get("bank_type"));
        payResult.setTotalFee(Integer.parseInt(map.get("total_fee")));
        payResult.setFeeType(map.get("fee_type"));
        payResult.setCashFee(Integer.parseInt(map.get("cash_fee")));
        if (map.containsKey("settlement_total_fee")) {
            payResult.setSettlementTotalFee(Integer.parseInt(map.get("settlement_total_fee")));
        }
        if (map.containsKey("cash_fee_type")) {
            payResult.setCashFeeType(map.get("cash_fee_type"));
        }
        if (map.containsKey("coupon_fee")) {
            payResult.setCouponFee(Integer.parseInt(map.get("coupon_fee")));
        }
        if (map.containsKey("coupon_count")) {
            payResult.setCouponCount(Integer.parseInt(map.get("coupon_count")));
            List<Coupon> coupons = new ArrayList<>();
            for (int i = 0; i < payResult.getCouponCount(); i++) {
                Coupon coupon = new Coupon();
                coupon.setCouponId(map.get("coupon_id_" + i));
                coupon.setCouponType(map.get("coupon_type_" + i));
                coupon.setCouponFee(Integer.parseInt(map.get("coupon_fee_" + i)));
                coupons.add(coupon);
            }
            payResult.setCoupons(coupons);
        }
        payResult.setAttach(map.get("attach"));
        return payResult;
    }
}
